home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #1 / Amiga Plus 1995 #1.iso / testprogramme / diskspeed / src / mks_list.c < prev    next >
C/C++ Source or Header  |  1994-12-13  |  20KB  |  687 lines

  1. /*
  2.  * MKSoft Display List Gadget - Copyright (c) 1989, 1990 by MKSoft Development
  3.  *
  4.  *                          DiskSpeed v4.2
  5.  *                          ScsiSpeed v4.2
  6.  *                                by
  7.  *                           Michael Sinz
  8.  *
  9.  *            Copyright (c) 1989-1992 by MKSoft Development
  10.  *
  11.  *            MKSoft Development
  12.  *            163 Appledore Drive
  13.  *            Downingtown, PA 19335
  14.  *
  15.  * Yes, this is yet another disk speed testing program, but with a few
  16.  * differences.  It was designed to give the most accurate results of the
  17.  * true disk performance in the system.  For this reason many of
  18.  * DiskSpeed's results may look either lower or higher than current disk
  19.  * performance tests.
  20.  *
  21.  ******************************************************************************
  22.  *                                          *
  23.  *    Reading legal mush can turn your brain into guacamole!              *
  24.  *                                          *
  25.  *        So here is some of that legal mush:                  *
  26.  *                                          *
  27.  * Permission is hereby granted to distribute this program's source          *
  28.  * executable, and documentation for non-commercial purposes, so long as the  *
  29.  * copyright notices are not removed from the sources, executable or          *
  30.  * documentation.  This program may not be distributed for a profit without   *
  31.  * the express written consent of the author Michael Sinz.              *
  32.  *                                          *
  33.  * This program is not in the public domain.                      *
  34.  *                                          *
  35.  * Fred Fish is expressly granted permission to distribute this program's     *
  36.  * source and executable as part of the "Fred Fish freely redistributable     *
  37.  * Amiga software library."                              *
  38.  *                                          *
  39.  * Permission is expressly granted for this program and it's source to be     *
  40.  * distributed as part of the Amicus Amiga software disks, and the          *
  41.  * First Amiga User Group's Hot Mix disks.                      *
  42.  *                                          *
  43.  ******************************************************************************
  44.  */
  45.  
  46. #include    <exec/types.h>
  47. #include    <exec/lists.h>
  48. #include    <exec/nodes.h>
  49. #include    <exec/memory.h>
  50. #include    <graphics/text.h>
  51. #include    <intuition/intuition.h>
  52.  
  53. #include    <clib/intuition_protos.h>
  54. #include    <clib/exec_protos.h>
  55. #include    <clib/graphics_protos.h>
  56. #include    <clib/layers_protos.h>
  57.  
  58. #include    <pragmas/intuition_pragmas.h>
  59. #include    <pragmas/exec_pragmas.h>
  60. #include    <pragmas/graphics_pragmas.h>
  61. #include    <pragmas/layers_pragmas.h>
  62.  
  63. #include    <string.h>
  64.  
  65. #include    "MKS_List.h"
  66. #include    "MakeBoxes.h"
  67.  
  68. extern    struct    Library    *SysBase;
  69. extern    struct    Library    *IntuitionBase;
  70. extern    struct    Library    *GfxBase;
  71. extern    struct    Library    *LayersBase;
  72.  
  73. /*
  74.  * This is the "real" DisplayList structure...
  75.  */
  76. struct    RealDisplayList
  77. {
  78.     /*
  79.      * These fields are from the public structure...
  80.      */
  81.     struct    DisplayList    DisplayList;
  82.  
  83.     /*
  84.      * The following fields are *NOT* public and are
  85.      * 100% maintained by the list gadget...
  86.      */
  87.     struct    Node        *Top;
  88.     struct    MinList        *TheList;
  89.         SHORT        TopNum;
  90.         SHORT        ListSize;
  91.         SHORT        DisplaySize;    /* Number of display lines */
  92.         SHORT        LineYSize;
  93.  
  94.     struct    Region        *Region;
  95.     struct    Rectangle    Rectangle;
  96.  
  97.     struct    IntuiText    Text;
  98.     struct    TextAttr    TextStyle;
  99.     struct    TextFont    *TheFont;
  100.  
  101.     struct    Gadget        ListGadget;
  102.     struct    Gadget        UpGadget;
  103.     struct    Gadget        DnGadget;
  104.     struct    Gadget        PropGadget;
  105.  
  106.     struct    PropInfo    PropInfo;
  107.     struct    Image        PropImage;    /* For AutoKnob stuff... */
  108.  
  109.     struct    Border        ListGadgetBorders[4];
  110.     struct    Border        UpGadgetBorders[5];
  111.     struct    Border        DnGadgetBorders[5];
  112.         SHORT        ListGadgetVectors[5*2*4];
  113.  
  114.         UBYTE        FontName[1];
  115. };
  116.  
  117. /*
  118.  * Whenever we have "list" as a DisplayList, we have REAL_list as a RealDisplayList
  119.  */
  120. #define    REAL_list    ((struct RealDisplayList *)list)
  121.  
  122. #define    LIST_GADGET_ID    (0x7F01)
  123.  
  124. /*
  125.  * Vectors that display the arrows...
  126.  */
  127. static    SHORT    DnArrow_V[7*2]={4,3,7,0,0,0,3,3,6,1,2,1,3,2};
  128. static    SHORT    UpArrow_V[7*2]={4,0,7,3,0,3,3,0,6,2,2,2,3,1};
  129. static    SHORT    ArrowBoxTopLeft_V[5*2]={12,0,0,0,0,7,1,6,1,1};
  130. static    SHORT    ArrowBoxBottomRight_V[5*2]={1,7,13,7,13,0,12,1,12,6};
  131.  
  132. static    struct    Border    DnArrow={3,2,0,0,JAM1,7,DnArrow_V,NULL};
  133. static    struct    Border    UpArrow={3,2,0,0,JAM1,7,UpArrow_V,NULL};
  134.  
  135. /*
  136.  * These two DEFINEs help find the correct RastPort and BackFill colour
  137.  */
  138. #define    PICK_RASTPORT(window,list)    (window->RPort)
  139. #define    PICK_BACKFILL(list)        (0)
  140.  
  141. /*
  142.  * Just a quicky to help fill in the boarder structures...
  143.  */
  144. static void Do_Borders(struct Border *borders,UBYTE Highlight,UBYTE Shadow)
  145. {
  146.     borders[1].FrontPen=Highlight;
  147.     borders[1].DrawMode=JAM1;
  148.     borders[1].Count=5;
  149.     borders[1].XY=ArrowBoxTopLeft_V;
  150.     borders[1].NextBorder=&(borders[0]);
  151.     borders[2].FrontPen=Shadow;
  152.     borders[2].DrawMode=JAM1;
  153.     borders[2].Count=5;
  154.     borders[2].XY=ArrowBoxTopLeft_V;
  155.     borders[2].NextBorder=&(borders[0]);
  156.     borders[3].FrontPen=Shadow;
  157.     borders[3].DrawMode=JAM1;
  158.     borders[3].Count=5;
  159.     borders[3].XY=ArrowBoxBottomRight_V;
  160.     borders[3].NextBorder=&(borders[1]);
  161.     borders[4].FrontPen=Highlight;
  162.     borders[4].DrawMode=JAM1;
  163.     borders[4].Count=5;
  164.     borders[4].XY=ArrowBoxBottomRight_V;
  165.     borders[4].NextBorder=&(borders[2]);
  166. }
  167.  
  168. /*
  169.  * This routine deallocates the DisplayList allocated below...
  170.  * It does not do any unlinking...
  171.  */
  172. void FreeListGadget(struct DisplayList *list)
  173. {
  174.     if (list)
  175.     {
  176.         if (REAL_list->TheFont) CloseFont(REAL_list->TheFont);
  177.         if (REAL_list->Region) DisposeRegion(REAL_list->Region);
  178.         FreeMem(list,sizeof(struct RealDisplayList)+(LONG)strlen(REAL_list->FontName));
  179.     }
  180. }
  181.  
  182. /*
  183.  * This routine allocates and initializes a DisplayList gadget...
  184.  * It will link the gadgets into the gadget list given...
  185.  *
  186.  * Arguments:  TextAttr,**Gadget,TextPen,Highlight,Shadow,Left,Top,Width,Height
  187.  */
  188. struct DisplayList *InitListGadget(struct TextAttr *ta,struct Gadget **gad,UBYTE TextPen,UBYTE Highlight,UBYTE Shadow,SHORT Left,SHORT Top,SHORT Width,SHORT Height)
  189. {
  190. register    struct    RealDisplayList    *rlist;
  191. register        SHORT        tmp;
  192.  
  193.     if (rlist=AllocMem(sizeof(struct RealDisplayList)+(LONG)strlen(ta->ta_Name),MEMF_PUBLIC|MEMF_CLEAR))
  194.     {
  195.         if (rlist->Region=NewRegion())
  196.         {
  197.             rlist->DisplaySize=(Height-4) / (rlist->LineYSize=((ta->ta_YSize)+2));
  198.  
  199.             /*
  200.              * Make borders for the main list box...
  201.              */
  202.             rlist->ListGadgetBorders[0].FrontPen=Shadow;
  203.             rlist->ListGadgetBorders[0].DrawMode=JAM1;
  204.             rlist->ListGadgetBorders[0].Count=5;
  205.             rlist->ListGadgetBorders[0].XY=&(rlist->ListGadgetVectors[0*5*2]);
  206.             rlist->ListGadgetBorders[0].NextBorder=&(rlist->ListGadgetBorders[1]);
  207.             FillTopLeft_Border(&(rlist->ListGadgetBorders[0]),Width-16,Height);
  208.  
  209.             rlist->ListGadgetBorders[1].FrontPen=Highlight;
  210.             rlist->ListGadgetBorders[1].DrawMode=JAM1;
  211.             rlist->ListGadgetBorders[1].Count=5;
  212.             rlist->ListGadgetBorders[1].XY=&(rlist->ListGadgetVectors[1*5*2]);
  213.             rlist->ListGadgetBorders[1].NextBorder=&(rlist->ListGadgetBorders[2]);
  214.             FillBottomRight_Border(&(rlist->ListGadgetBorders[1]),Width-16,Height);
  215.  
  216.             /*
  217.              * Make borders for the prop gadget area...
  218.              * This is linked to the main list box since the prop gadget
  219.              * will be just a borderless AutoKnob...
  220.              */
  221.             rlist->ListGadgetBorders[2].LeftEdge=Width-14;
  222.             rlist->ListGadgetBorders[2].FrontPen=Highlight;
  223.             rlist->ListGadgetBorders[2].DrawMode=JAM1;
  224.             rlist->ListGadgetBorders[2].Count=5;
  225.             rlist->ListGadgetBorders[2].XY=&(rlist->ListGadgetVectors[2*5*2]);
  226.             rlist->ListGadgetBorders[2].NextBorder=&(rlist->ListGadgetBorders[3]);
  227.             FillTopLeft_Border(&(rlist->ListGadgetBorders[2]),14,Height-16);
  228.  
  229.             rlist->ListGadgetBorders[3].LeftEdge=Width-14;
  230.             rlist->ListGadgetBorders[3].FrontPen=Shadow;
  231.             rlist->ListGadgetBorders[3].DrawMode=JAM1;
  232.             rlist->ListGadgetBorders[3].Count=5;
  233.             rlist->ListGadgetBorders[3].XY=&(rlist->ListGadgetVectors[3*5*2]);
  234.             rlist->ListGadgetBorders[3].NextBorder=NULL;
  235.             FillBottomRight_Border(&(rlist->ListGadgetBorders[3]),14,Height-16);
  236.  
  237.             /*
  238.              * The main list gadget...
  239.              */
  240.             rlist->ListGadget.LeftEdge=Left;
  241.             rlist->ListGadget.TopEdge=Top;
  242.             rlist->ListGadget.Width=0;
  243.             rlist->ListGadget.Height=0;
  244.             rlist->ListGadget.Flags=GADGHNONE;
  245.             rlist->ListGadget.Activation=0;
  246.             rlist->ListGadget.GadgetType=BOOLGADGET;
  247.             rlist->ListGadget.GadgetRender=(APTR)&(rlist->ListGadgetBorders[0]);
  248.             rlist->ListGadget.GadgetID=LIST_GADGET_ID;
  249.             rlist->ListGadget.UserData=(APTR)rlist;
  250.  
  251.             /*
  252.              * The AutoKnob is Borderless since we will be making
  253.              * our own 3-D style border...
  254.              */
  255.             rlist->PropInfo.Flags=AUTOKNOB|FREEVERT|PROPBORDERLESS;
  256.             rlist->PropInfo.HorizBody=MAXBODY;
  257.             rlist->PropInfo.VertBody=MAXBODY;
  258.             rlist->PropGadget.LeftEdge=Left+Width-11;
  259.             rlist->PropGadget.TopEdge=Top+2;
  260.             rlist->PropGadget.Width=8;
  261.             rlist->PropGadget.Height=Height-20;
  262.             rlist->PropGadget.Flags=GADGIMAGE;
  263.             rlist->PropGadget.Activation=GADGIMMEDIATE|RELVERIFY|FOLLOWMOUSE;
  264.             rlist->PropGadget.GadgetType=PROPGADGET;
  265.             rlist->PropGadget.GadgetRender=(APTR)&(rlist->PropImage);
  266.             rlist->PropGadget.SpecialInfo=(APTR)&(rlist->PropInfo);
  267.             rlist->PropGadget.GadgetID=LIST_GADGET_ID;
  268.             rlist->PropGadget.UserData=(APTR)rlist;
  269.  
  270.             /*
  271.              * Set up the Up and Down arrow gadgets...
  272.              */
  273.             rlist->UpGadgetBorders[0]=UpArrow;
  274.             rlist->UpGadgetBorders[0].FrontPen=TextPen;
  275.             Do_Borders(rlist->UpGadgetBorders,Highlight,Shadow);
  276.             rlist->UpGadget.LeftEdge=Left+Width-14;
  277.             rlist->UpGadget.TopEdge=Top+Height-16;
  278.             rlist->UpGadget.Width=14;
  279.             rlist->UpGadget.Height=8;
  280.             rlist->UpGadget.Flags=((Shadow!=Highlight) ? GADGHIMAGE : GADGHCOMP);
  281.             rlist->UpGadget.Activation=RELVERIFY|GADGIMMEDIATE;
  282.             rlist->UpGadget.GadgetType=BOOLGADGET;
  283.             rlist->UpGadget.GadgetRender=(APTR)&(rlist->UpGadgetBorders[3]);
  284.             rlist->UpGadget.SelectRender=(APTR)&(rlist->UpGadgetBorders[4]);
  285.             rlist->UpGadget.GadgetID=LIST_GADGET_ID;
  286.             rlist->UpGadget.UserData=(APTR)rlist;
  287.  
  288.             rlist->DnGadgetBorders[0]=DnArrow;
  289.             rlist->DnGadgetBorders[0].FrontPen=TextPen;
  290.             Do_Borders(rlist->DnGadgetBorders,Highlight,Shadow);
  291.             rlist->DnGadget.LeftEdge=Left+Width-14;
  292.             rlist->DnGadget.TopEdge=Top+Height-8;
  293.             rlist->DnGadget.Width=14;
  294.             rlist->DnGadget.Height=8;
  295.             rlist->DnGadget.Flags=((Shadow!=Highlight) ? GADGHIMAGE : GADGHCOMP);
  296.             rlist->DnGadget.Activation=RELVERIFY|GADGIMMEDIATE;
  297.             rlist->DnGadget.GadgetType=BOOLGADGET;
  298.             rlist->DnGadget.GadgetRender=(APTR)&(rlist->DnGadgetBorders[3]);
  299.             rlist->DnGadget.SelectRender=(APTR)&(rlist->DnGadgetBorders[4]);
  300.             rlist->DnGadget.GadgetID=LIST_GADGET_ID;
  301.             rlist->DnGadget.UserData=(APTR)rlist;
  302.  
  303.             /*
  304.              * Set up the rectangle and clipping area for the list box
  305.              */
  306.             rlist->Rectangle.MaxX=(rlist->Rectangle.MinX=(rlist->ListGadget.LeftEdge)+3)+Width-25;
  307.             rlist->Rectangle.MaxY=(rlist->Rectangle.MinY=(rlist->ListGadget.TopEdge)+2)+Height-5;
  308.  
  309.             /*
  310.              * We want to CENTER the rectangle based on the number of
  311.              * text lines and the text hight.
  312.              */
  313.             tmp=(rlist->Rectangle.MaxY)-(rlist->Rectangle.MinY)+1;
  314.             tmp-=(rlist->DisplaySize)*(rlist->LineYSize);
  315.             if (tmp>0)
  316.             {
  317.                 rlist->Rectangle.MinY+=(tmp>>1);
  318.                 rlist->Rectangle.MaxY-=((tmp+1)>>1);
  319.             }
  320.  
  321.             /*
  322.              * Pre-initialize the Intuitext structure as much as possible...
  323.              */
  324.             rlist->Text.FrontPen=TextPen;
  325.             rlist->Text.DrawMode=JAM1;
  326.             rlist->Text.LeftEdge=1;
  327.             rlist->Text.TopEdge=1;
  328.             rlist->Text.ITextFont=&(rlist->TextStyle);
  329.  
  330.             /*
  331.              * Make a copy of the TextAttr for the list display
  332.              */
  333.             rlist->TextStyle=*ta;
  334.             strcpy(rlist->TextStyle.ta_Name=rlist->FontName,ta->ta_Name);
  335.  
  336.             /*
  337.              * Open the font so it stays around...
  338.              * Since the font had to be open when called, this just gets
  339.              * another open on it.  The clean up routine closes this...
  340.              */
  341.             rlist->TheFont=OpenFont(&(rlist->TextStyle));
  342.  
  343.             /*
  344.              * Now, pre-build the region for better speed...
  345.              */
  346.             if (!OrRectRegion(rlist->Region,&(rlist->Rectangle)))
  347.             {
  348.                 FreeListGadget((struct DisplayList *)rlist);
  349.                 rlist=NULL;
  350.             }
  351.         }
  352.         else
  353.         {
  354.             FreeListGadget((struct DisplayList *)rlist);
  355.             rlist=NULL;
  356.         }
  357.     }
  358.     if (rlist)
  359.     {
  360.         rlist->ListGadget.NextGadget=*gad;
  361.         rlist->PropGadget.NextGadget=&(rlist->ListGadget);
  362.         rlist->UpGadget.NextGadget=&(rlist->PropGadget);
  363.         rlist->DnGadget.NextGadget=&(rlist->UpGadget);
  364.         *gad=&(rlist->DnGadget);
  365.     }
  366.     return((struct DisplayList *)rlist);
  367. }
  368.  
  369. /*
  370.  * This routine updates the prop gadget for the list given...
  371.  */
  372. static void UpDate_Prop(struct Window *window,struct DisplayList *list)
  373. {
  374. register    long    diffsize;
  375.  
  376.     diffsize=(REAL_list->ListSize)-(REAL_list->DisplaySize);
  377.  
  378.     if (diffsize>0)
  379.     {
  380.         NewModifyProp(&(REAL_list->PropGadget),window,NULL,REAL_list->PropInfo.Flags,
  381.                 0,
  382.                 (USHORT)(((0xffffL)*(REAL_list->TopNum)+(diffsize>>1))/diffsize),
  383.  
  384.                 0xffff,
  385.                 (USHORT)(((0xffffL)*(REAL_list->DisplaySize))/(REAL_list->ListSize)),
  386.  
  387.                 1L);
  388.     }
  389.     else
  390.     {
  391.         NewModifyProp(&(REAL_list->PropGadget),window,NULL,REAL_list->PropInfo.Flags,
  392.                 0,
  393.                 0,
  394.  
  395.                 0xffff,
  396.                 0xffff,
  397.  
  398.                 1L);
  399.     }
  400. }
  401.  
  402. /*
  403.  * This routine takes the NewTop and sets it into the TopNum and
  404.  * positions *Top to the right node value...
  405.  *
  406.  * Note:  Since this routine does not do ERROR checking, the NewTop value
  407.  *        and TheList *MUST* be valid...
  408.  */
  409. static void SetTopPointer(struct DisplayList *list,SHORT NewTop)
  410. {
  411. struct    Node    *item;
  412.  
  413.     REAL_list->TopNum=NewTop;
  414.     item=(struct Node *)(REAL_list->TheList->mlh_Head);
  415.  
  416.     while(NewTop)
  417.     {
  418.         item=(struct Node *)(item->ln_Succ);
  419.         NewTop--;
  420.     }
  421.     REAL_list->Top=item;
  422. }
  423.  
  424. /*
  425.  * This routine will display the line number given...  (Display line number)
  426.  *
  427.  * If the line is selected, it will be inverted via a Complement RectFill
  428.  *
  429.  * All actions will be clipped via a ClipRect that this routine installs.
  430.  */
  431. static void DisplayLine(struct RastPort *rp,struct DisplayList *list,SHORT line)
  432. {
  433. register    struct    Region    *r;
  434. register    struct    Node    *item;
  435. register        SHORT    y;
  436. register        SHORT    y1;
  437.  
  438.     if ((line>=0)&&(line<(REAL_list->DisplaySize)))
  439.     {
  440.         /*
  441.          * Set up clipping rectangle within the borders of the gadget...
  442.          */
  443.         r=InstallClipRegion(rp->Layer,REAL_list->Region);
  444.  
  445.         y1=(y=(REAL_list->Rectangle.MinY)+(line*(REAL_list->LineYSize)))+(REAL_list->LineYSize)-1;
  446.  
  447.         SetAPen(rp,PICK_BACKFILL(REAL_list));
  448.         SetDrMd(rp,JAM1);
  449.         RectFill(rp,REAL_list->Rectangle.MinX,y,REAL_list->Rectangle.MaxX,y1);
  450.  
  451.         if (item=REAL_list->Top)
  452.         {
  453.             while (line>0)
  454.             {
  455.                 if (item->ln_Succ)
  456.                 {
  457.                     item=(struct Node *)(item->ln_Succ);
  458.                     line--;
  459.                 }
  460.                 else line=0;
  461.             }
  462.             if (item->ln_Succ)
  463.             {
  464.                 REAL_list->Text.IText=item->ln_Name;
  465.                 PrintIText(rp,&(REAL_list->Text),REAL_list->Rectangle.MinX,y);
  466.             }
  467.         }
  468.  
  469.         InstallClipRegion(rp->Layer,r);
  470.     }
  471. }
  472.  
  473. /*
  474.  * This routine will clear the list box to the backfill colour...
  475.  */
  476. static void ClearDisplayBox(struct RastPort *rp,struct DisplayList *list)
  477. {
  478.     SetAPen(rp,PICK_BACKFILL(REAL_list));
  479.     SetDrMd(rp,JAM1);
  480.     RectFill(rp,    REAL_list->Rectangle.MinX,REAL_list->Rectangle.MinY,
  481.             REAL_list->Rectangle.MaxX,REAL_list->Rectangle.MaxY);
  482. }
  483.  
  484. /*
  485.  * This routine displays all of the lines in the list...
  486.  */
  487. static void DisplayAllLines(struct RastPort *rp,struct DisplayList *list)
  488. {
  489. register    SHORT    line;
  490.  
  491.     for (line=0;line<(REAL_list->DisplaySize);line++) DisplayLine(rp,list,line);
  492. }
  493.  
  494. /*
  495.  * This routine moves the list UP or DOWN to the line number give.
  496.  *
  497.  * It will try to make sure that this is done as best as possible...
  498.  * It will update the prop gadget if it is not active...
  499.  */
  500. static void MoveList(struct Window *window,struct DisplayList *list,SHORT line)
  501. {
  502. register    struct    RastPort    *rp;
  503. register        SHORT        newline;
  504.  
  505.     newline=line+(REAL_list->TopNum);
  506.     if (newline<0) line=0-(REAL_list->TopNum);
  507.     else if (newline>((REAL_list->ListSize)-(REAL_list->DisplaySize)))
  508.     {
  509.         line=(REAL_list->ListSize)-(REAL_list->DisplaySize)-(REAL_list->TopNum);
  510.         if (line<0) line=0;
  511.     }
  512.  
  513.     if (line)
  514.     {
  515.         rp=PICK_RASTPORT(window,REAL_list);
  516.         SetTopPointer(list,line+(REAL_list->TopNum));
  517.         if (line>0) newline=line;
  518.         else newline=0-line;
  519.  
  520.         if ((newline*11)>(8*(REAL_list->DisplaySize)))
  521.         {
  522.             DisplayAllLines(rp,list);
  523.         }
  524.         else
  525.         {
  526.             SetDrMd(rp,JAM2);
  527.             SetBPen(rp,PICK_BACKFILL(REAL_list));
  528.  
  529.             ScrollRaster(rp,0,line*(REAL_list->LineYSize),
  530.                     REAL_list->Rectangle.MinX,REAL_list->Rectangle.MinY,
  531.                     REAL_list->Rectangle.MaxX,REAL_list->Rectangle.MaxY);
  532.  
  533.             if (line<0)
  534.             {
  535.                 newline=0-line;
  536.                 line=0;
  537.             }
  538.             else
  539.             {
  540.                 newline=REAL_list->DisplaySize;
  541.                 line=(REAL_list->DisplaySize)-line;
  542.             }
  543.             while (line<newline) DisplayLine(rp,list,line++);
  544.         }
  545.         if (!((REAL_list->PropGadget.Flags)&SELECTED)) UpDate_Prop(window,list);
  546.     }
  547. }
  548.  
  549. /*
  550.  * This routine will initialize a fresh list.  It clears Selected,
  551.  * counts the entries, sets top of the display such that the bottom
  552.  * of the list is displayed and displays the list...
  553.  */
  554. void FreshList(struct Window *window,struct DisplayList *list,struct MinList *newlist)
  555. {
  556. register    struct    Node    *item;
  557. register        SHORT    count;
  558.  
  559.     REAL_list->TheList=newlist;
  560.     REAL_list->Top=REAL_list->DisplayList.Selected=NULL;
  561.     count=0;
  562.     if (newlist)
  563.     {
  564.         item=(struct Node *)(REAL_list->TheList->mlh_Head);
  565.         while (item=(struct Node *)(item->ln_Succ)) count++;
  566.         SetTopPointer(list,(count > REAL_list->DisplaySize) ? count-REAL_list->DisplaySize : 0);
  567.     }
  568.     REAL_list->ListSize=count;
  569.     UpDate_Prop(window,list);
  570.     DisplayAllLines(PICK_RASTPORT(window,REAL_list),REAL_list);
  571. }
  572.  
  573. /*
  574.  * This routine loops while one of the arrow gadgets is pressed and will
  575.  * advance the display accordingly.
  576.  */
  577. static void ArrowGadgetLoop(struct Window *window,struct DisplayList *list,struct Gadget *gad,SHORT change)
  578. {
  579. register    struct    IntuiMessage    *msg;
  580. register        ULONG        old_IDCMP;
  581. register        SHORT        tick_count;
  582. register        SHORT        flag=TRUE;
  583.  
  584.     old_IDCMP=window->IDCMPFlags;
  585.     ModifyIDCMP(window,MOUSEBUTTONS|GADGETUP|INTUITICKS);
  586.  
  587.     MoveList(window,list,change);
  588.     tick_count=-3;
  589.  
  590.     while(flag)
  591.     {
  592.         WaitPort(window->UserPort);
  593.         if (msg=(struct IntuiMessage *)GetMsg(window->UserPort))
  594.         {
  595.             switch (msg->Class)
  596.             {
  597.             case MOUSEBUTTONS:    if (msg->Code==SELECTUP) flag=FALSE;
  598.                         break;
  599.             case GADGETUP:        flag=FALSE;
  600.                         break;
  601.             case INTUITICKS:    tick_count++;
  602.                         if ((tick_count>0)&&(gad->Flags&SELECTED))
  603.                         {
  604.                             MoveList(window,list,change);
  605.                         }
  606.                         break;
  607.             }
  608.             ReplyMsg((struct Message *)msg);
  609.         }
  610.     }
  611.  
  612.     ModifyIDCMP(window,old_IDCMP);
  613. }
  614.  
  615. /*
  616.  * This routine moves the list to match the prop gadget...
  617.  */
  618. static void MoveToProp(struct Window *window,struct DisplayList *list)
  619. {
  620. register    ULONG    tmp;
  621.  
  622.     if ((tmp=((REAL_list->ListSize)-(REAL_list->DisplaySize)))>0)
  623.     {
  624.         tmp=(tmp*(ULONG)(REAL_list->PropInfo.VertPot)+(0xffffL >> 1))/0xffffL;
  625.         MoveList(window,list,(SHORT)tmp-(REAL_list->TopNum));
  626.     }
  627. }
  628.  
  629. /*
  630.  * This routine is entered on GADGETDOWN on the PropGadget and
  631.  * it loops until the user releases it.  It updates the display
  632.  * as needed by user actions...
  633.  */
  634. static void PropGadgetLoop(struct Window *window,struct DisplayList *list)
  635. {
  636. register    struct    IntuiMessage    *msg;
  637. register        ULONG        old_IDCMP;
  638. register        SHORT        flag=TRUE;
  639.  
  640.     old_IDCMP=window->IDCMPFlags;
  641.     ModifyIDCMP(window,GADGETUP|MOUSEMOVE);
  642.  
  643.     while(flag)
  644.     {
  645.         msg=(struct IntuiMessage *)WaitPort(window->UserPort);
  646.         while ((flag)&&(msg)) if (msg=(struct IntuiMessage *)GetMsg(window->UserPort))
  647.         {
  648.             if (msg->Class==GADGETUP) flag=FALSE;
  649.             ReplyMsg((struct Message *)msg);
  650.         }
  651.         MoveToProp(window,list);
  652.     }
  653.  
  654.     ModifyIDCMP(window,old_IDCMP);
  655. }
  656.  
  657. /*
  658.  * This is the InputEvent filter...
  659.  * Call this routine with each message.  If it returns a pointer to
  660.  * a DisplayList, a message was processed, if it returns NULL, nothing
  661.  * was done with the message and you may need to process it.
  662.  * The message is NOT ReplyMsg()ed...
  663.  */
  664. struct DisplayList *Check_ListGadget(struct Window *window,struct IntuiMessage *message)
  665. {
  666. register    struct    Gadget        *gad;
  667. register    struct    DisplayList    *list=NULL;
  668.  
  669.     if (message)
  670.     {
  671.         if (message->Class==GADGETDOWN)
  672.         {
  673.             gad=(struct Gadget *)(message->IAddress);
  674.             if (gad->GadgetID==LIST_GADGET_ID)
  675.             {
  676.                 if (list=(struct DisplayList *)(gad->UserData))
  677.                 {
  678.                     if (&(REAL_list->PropGadget)==gad) PropGadgetLoop(window,list);
  679.                     else if (&(REAL_list->UpGadget)==gad) ArrowGadgetLoop(window,list,gad,-1);
  680.                     else if (&(REAL_list->DnGadget)==gad) ArrowGadgetLoop(window,list,gad,1);
  681.                 }
  682.             }
  683.         }
  684.     }
  685.     return(list);
  686. }
  687.